package online.filter.deploy.struts;

import java.io.IOException;
import java.util.Iterator;
import java.util.Objects;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import online.filter.deploy.S2HotDeployClassLoader;
import online.filter.deploy.S2HotDeployUtil;

import org.apache.commons.chain2.CatalogFactory;
import org.apache.commons.chain2.Context;
import org.apache.commons.chain2.impl.CatalogFactoryBase;

/**
 * HotDeployクラス
 *
 * @author Tadashi Nakayama
 * @version 1.0.0
 */
public final class S2HotDeployChainConfigFilter implements Filter {

	/** 対象パッケージ */
	private String[] inc = null;
	/** 対象外パッケージ */
	private String[] exc = null;

	/**
	 * @see javax.servlet.Filter#destroy()
	 */
	@Override
	public void destroy() {
		return;
	}

	/**
	 * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
	 * javax.servlet.ServletResponse, javax.servlet.FilterChain)
	 */
	@Override
	public void doFilter(final ServletRequest request, final ServletResponse response,
					final FilterChain chain) throws IOException, ServletException {
		String clazz = S2HotDeployChainConfigFilter.class.getName();

		ClassLoader org = Thread.currentThread().getContextClassLoader();
		try {
			if (request.getAttribute(clazz) == null) {
				ClassLoader cl = getClassLoader(org);
				try {
					CatalogFactory<String, Object, Context<String, Object>> cf =
									CatalogFactoryBase.getInstance();

					Thread.currentThread().setContextClassLoader(cl);

					setCatalog(cf);

					request.setAttribute(clazz, cl);
					chain.doFilter(request, response);

				} finally {
					request.removeAttribute(clazz);
					CatalogFactoryBase.clear();
				}
			} else {
				ClassLoader cl = ClassLoader.class.cast(request.getAttribute(clazz));
				Thread.currentThread().setContextClassLoader(cl);

				chain.doFilter(request, response);
			}
		} finally {
			Thread.currentThread().setContextClassLoader(org);
		}
	}

	/**
	 * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
	 */
	@Override
	public void init(final FilterConfig filterConfig) throws ServletException {
		String val = filterConfig.getInitParameter("include");
		if (!Objects.toString(val, "").isEmpty()) {
			this.inc = val.split(",");
		}
		val = filterConfig.getInitParameter("exclude");
		if (!Objects.toString(val, "").isEmpty()) {
			this.exc = val.split(",");
		}

		S2HotDeployUtil.setClassPath(filterConfig.getServletContext());
	}

	/**
	 * クラスローダ取得
	 *
	 * @param org 親クラスローダ
	 * @return クラスローダ
	 */
	private ClassLoader getClassLoader(final ClassLoader org) {
		return new S2HotDeployClassLoader(org, this.inc, this.exc);
	}

	/**
	 * 初期設定
	 *
	 * @param cf カタログファクトリ
	 */
	private void setCatalog(final CatalogFactory<String, Object, Context<String, Object>> cf) {
		CatalogFactory<String, Object, Context<String, Object>> factory =
						CatalogFactoryBase.getInstance();

		for (Iterator<String> it = cf.getNames(); it.hasNext();) {
			String name = it.next();
			factory.addCatalog(name, cf.getCatalog(name));
		}
	}
}
